﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Serialization;
using Utilify.Framework;
using Utilify.Platform.Demo.RayTracer.Model;

using ExecutionContext = Utilify.Framework.ExecutionContext;

namespace Utilify.Platform.Demo.RayTracer
{
    [Serializable]
    public class AdditionJob : IExecutable, IDependent //, IResults 
    {

        private const String InputFilename = "Request.xml";
        private String _outputFilename;
        private const String HistoryFilename = "History.xml";
        private int _valueA;
        private int _valueB;
        private int _result;
        private string _workingdirectory;
        private int _inputValue;
        private RequestConfig _request;
        private RequestConfig _jobConfig;
        private string _remoteFile;
        private ExecutionContext _context;
        private static UtilifyClassesDataContext _dataClasses;
        private string _databaseDependencyFile;
        private StreamWriter writer;
        private Result _remoteResult;

        private const String connectionString =
            "Data Source=192.168.0.104\\AVICENNEDB;Network Library=DBMSSOCN;Initial Catalog=UtilifyPlatform;User ID=Utilify;Password=utilify;";

        private List<String> _results;
        private List<String> _history;
        private String _workerName;
        private String _startTime;
        private static Queue<String> _queries;


        #region logging procedure


        public void TraceThat(string message)
        {
            writer =
                new StreamWriter(
                    Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + _valueA + ".txt", true);

            // writer = new StreamWriter("Log"+_valueA + ".txt", true);

            writer.WriteLine(DateTime.Now.TimeOfDay + "     " + message);
            writer.Close();
        }

        #endregion

      

        #region  Input & Output Dependencies Definition


        //Defines the job's input dependencies' files to the main program, making it able to send them to remote jobs
        public DependencyInfo[] GetDependencies()
        {


            // DependencyInfo info = new DependencyInfo("17B4EF61-1CCF-493F-8708-A00400E7285F", InputFilename, "testData/" + InputFilename, new DateTime(long.Parse("634659386187446900")), 2,DependencyType.DataFile,"4a44dc15364204a80fe80e9039455cc1608281820fe2b24f1e5233ade6af1dd5");
            // var dependencyInfo = new DependencyInfo(InputFilename, InputFilename, DependencyType.DataFile);

            var dependencyInfo = new DependencyInfo(_remoteFile, _remoteFile, DependencyType.DataFile);
            TraceThat("input dependencies added");

            return new[] {dependencyInfo};
        }



/*

        //Gest remote results to the luncher application to store it on single file later 
        public ResultInfo[] GetExpectedResults()
        {
            ResultInfo outputResultInfo = new ResultInfo(_outputFilename, ResultRetrievalMode.BackToOrigin);
            //  ResultInfo historyResultInfo = new ResultInfo(HistoryFilename, ResultRetrievalMode.BackToOrigin);
            TraceThat("output dependencies added");
            return new ResultInfo[] {outputResultInfo}; //, historyResultInfo };
        }
*/



        #endregion





        #region The Job



        // Job Constructor
        public AdditionJob(int valueA, int valueB, RequestConfig requestConfig, string remoteFile)
        {
            // this._startTime = DateTime.Now.ToShortTimeString();

            this._valueA = valueA;
            this._valueB = valueB;
            this._request = requestConfig;
            this._remoteFile = remoteFile;
            this._outputFilename = "Result" +_valueA + ".xml";
            TraceThat("ok");
            
        }



        //Job's Main Loop 
        public void Execute(ExecutionContext context)
        {
            TraceThat("--main loop entry point--");
            //This line is optional, meant to assign the local variable for future use 
            //We recommand writing function using context informations after this line 
            _context = context;



            TraceThat("context loader");

            DeserializeRemoteFile(context);

            TraceThat("file deserialized");
            try
            {
                /*  Thread myThread;
                  myThread = new Thread(new ThreadStart(QueryDatabase));

                  // Lancement du thread
                  myThread.Start();*/

                QueryDatabase(context);
                TraceThat("database queried");
            }
            catch (Exception ex)
            {

                TraceThat(ex.Message);
            }




            if (ProcessConfig())
            {
                this._result = this._valueA + this._valueB + this._inputValue;
            }
            else
            {
                this._result = this._valueA + this._valueB;
                TraceThat(_result + " calculated");
                context.Log.AppendLine(String.Format("Adding {0} and {1}", _valueA, _valueB));
            }


            // Adapt result to xml via serializable class
            _remoteResult = new Result(_valueA,_workerName,_result.ToString(),context.JobId);
            
            //save file 
         //  SaveDistributedFile(context, _outputFilename, _results);

            //Thread.Sleep(20000);
        }


        #endregion


        #region Remote I/O  Operations

        // not activated
        private bool LoadDistributedFile(ExecutionContext context)
        {
            bool fileLoaded = false;
            //Get the file distrubuted for all the remote process 
            String inputPath = Path.Combine(context.WorkingDirectory, InputFilename);
            _workingdirectory = inputPath;

            if (File.Exists(inputPath))
            {
                //Try read extra number to add from file
                String[] inputValues = File.ReadAllLines(inputPath);
                Int32.TryParse(inputValues[0], out _inputValue);
                fileLoaded = Int32.TryParse(inputValues[0], out _inputValue);
            }

            return fileLoaded;
        }

        //--
        public bool ProcessConfig()
        {
            // Extracting data from the XML Request config file after being deserialized to "_request" object 
            if (_request != null)
            {
                string temp;
                temp = _request.Pilars[_valueA%_request.Pilars.Count];
                temp = temp.Remove(temp.Length - 1);
                return Int32.TryParse(temp, out _inputValue);
            }
            else
                return false;
        }






        private bool SaveDistributedFile(ExecutionContext context, String resultFilename, List<String> resultOperations)
        {
            string resultPath = Path.Combine(context.WorkingDirectory, resultFilename);
            TraceThat(resultPath);

            StreamWriter streamwriter ;
            try
            {
              streamwriter = new StreamWriter(resultPath, false);
              streamwriter.WriteLine("test");
              TraceThat("write successful");
              streamwriter.Close();
            }
            catch (Exception e)
            {
                
                TraceThat("Exception "+e.Message);
            }
           

            // writer = new StreamWriter("Log"+_valueA + ".txt", true);

            


            /*     foreach (String result in resultOperations)
                    {
                        writer.WriteLine(result);
                    }
                */
                 
            
            return false;
        }


        #endregion


        #region  Fields getters



        public int GetResult()
        {
            TraceThat("result returned");
            return this._result;
        }


        public int GetValueA()
        {
            return this._valueA;
        }

        public int GetValueB()
        {
            return this._valueB;
        }



        public string GetWorkingDirectory()
        {
            return _workingdirectory;
        }


        public int GetInputValue()
        {
            return _inputValue;
        }


        public string DatabaseDependencyFile
        {
            get { return _databaseDependencyFile; }
        }


        public string GetConfigId()
        {
            //Get the id field from the job config object
            if (_jobConfig != null)
            {
                return _jobConfig.Id;
            }
            else return "";

        }


        public Result RemoteResult
        {
            get { return _remoteResult; }
        }

        public string WorkerName
        {
            set { _workerName = value; }
        }

        public string StartTime
        {
            set { _startTime = value; }
           
        }

        #endregion




        #region database queyring


        private void QueryDatabase(ExecutionContext context)
        {

            

            //Retrieve data from database
            /* _dataClasses = new UtilifyClassesDataContext("WASSIM\\SQLEXPRESS;Initial Catalog=UtilifyPlatform;Integrated Security=True" +
                        "");*/
            

            //Default value connects to the local database
            //_dataClasses = new UtilifyClassesDataContext();



           if (context == null)
           {
                _databaseDependencyFile = "context is empty";
                return;
            }

            UtilifyClassesDataContext _dataClasses1 = new UtilifyClassesDataContext();//connectionString);
            UtilifyClassesDataContext _dataClasses2 = new UtilifyClassesDataContext();//connectionString);
            String executorname = "empty";
            try
            {
                var query1 =
                    from dbJob in _dataClasses1.Jobs.AsEnumerable() where context.JobId == dbJob.id.ToString() 
                    join dbExecutor in _dataClasses2.Executors on dbJob.executorId equals dbExecutor.id
                    
                    select dbExecutor.uri;

                executorname = query1.FirstOrDefault();
            }
            catch (Exception ex)
            {
                TraceThat("Exception " +ex.Message);
                //_workerName = executorname;

            }
            executorname += " --";
            TraceThat("Executor name  " + executorname);
            _workerName = executorname;

            /*  var query1 =  from dbExecutor in _dataClasses.Executors
                             //  where dbExecutor.uri
                             select dbExecutor.uri;
               var firstOrDefault = query1.FirstOrDefault();*/
          


            /*
                        _dataClasses = new UtilifyClassesDataContext(connectionString);
                            var query2 = from dbUsr in _dataClasses.Usrs
                           select dbUsr.username;
                            if (firstOrDefault != null)
                            {
                              var  username = firstOrDefault.ToString();
                                TraceThat("Username  " + username);
                                user = username;
                            }*/

            // _databaseDependencyFile = executor + "  ---  "+ user;

            _databaseDependencyFile = _workerName;

            return;
        }



        #endregion


#region Adaptators



        //Every Job gets its remote specific xml file which contains the job specific configuration
        //this function deserialize the xml file into a local configuration object to use later
        private void DeserializeRemoteFile(ExecutionContext context)
        {

            TraceThat(_remoteFile);
            string filePath = Path.Combine(context.WorkingDirectory, _remoteFile);

            if (File.Exists(filePath))
            {
                //TraceThat(filePath);
                XmlSerializer serializer = new XmlSerializer(typeof(RequestConfig));
                StreamReader reader = new StreamReader(filePath);

                _jobConfig = (RequestConfig)serializer.Deserialize(reader);
            }
            else
            {
                _jobConfig = null;
            }

        
                
     }

      



#endregion




    }



}
